﻿using System;
using System.Reflection;
using System.Linq;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Microsoft.WindowsMobile.Samples.Location;
using KMLCreator;
using Mirkuz.Mapping;
using Mirkuz.PowerManagement;

namespace Mirkuz.TrailCompanion
{
    
    public partial class fMain : Form
    {
        Gps _gps = null;

        GpsPosition _CurrentPosition;
        UnattendedManager _uman=new UnattendedManager();
        IntPtr _gpspwrreq;
        TrainManager Training = new TrainManager();

        bool _gps_ok = false;        
        float SolSnrAvg = 0;
        float ViewSnrAvg = 0;

        string SettingsFileName = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "/mkrunner.xml";
        
        public fMain()
        {
            InitializeComponent();
        }

        private void fMain_Load(object sender, EventArgs e)
        {
            lblVersion.Text = " V:" + Assembly.GetExecutingAssembly().GetName().Version.ToString(4);
                        
            //carico valori target
            try
            {
                settingDataSet1.ReadXml(SettingsFileName);
            }
            catch { 
                settingDataSet1.Settings.AddSettingsRow(1500, 20);
                settingDataSet1.WriteXml(SettingsFileName);
            }            
            nmMaxMinutes.Value=settingDataSet1.Settings[0].MaxMinutes;
            nmMaxDistance.Value = settingDataSet1.Settings[0].MaxDistance;
            lblRemainingDistance.Text = nmMaxDistance.Value.ToString()+"m";

            Training.MaxDistance = settingDataSet1.Settings[0].MaxDistance; 
            Training.MaxRunningTime = TimeSpan.FromMinutes(settingDataSet1.Settings[0].MaxMinutes);
            lblRemainingTime.Text = Training.RemainingTime.Hours.ToString("00") + ":" + Training.RemainingTime.Minutes.ToString("00") + ":" + Training.RemainingTime.Seconds.ToString("00");

            _gpspwrreq=PowerManager.SetRequirement("GPD0:", CEDEVICE_POWER_STATE.D0);            
          
            _gps = new Gps();
            _gps.Open();                        

        }

        private void fMain_Closed(object sender, EventArgs e)
        {
            if (Training.IsRunning)
                Training.StopTraining();

            //salvataggio settings
            settingDataSet1.Settings[0].MaxDistance = (int)nmMaxDistance.Value;
            settingDataSet1.Settings[0].MaxMinutes = (int)nmMaxMinutes.Value;
            settingDataSet1.WriteXml(SettingsFileName);

            PowerManager.ReleaseRequirement(_gpspwrreq);

            _uman.Dispose();

            try
            {
                _gps.Close();
                _gps = null;
            }
            catch { }
        }

        private void cmdStart_Click(object sender, EventArgs e)
        {
            if (Training.IsRunning)
            {
                //fermo il training e salvo i dati
                Training.StopTraining();

                _uman.ReleaseUnattendedMode();

                SaveData();
                cmdStart.Text = "Start Training Session";
            }
            else
            {
                if (!_gps_ok)
                {
                    MessageBox.Show("No GPS Fix", "mkRunner", MessageBoxButtons.OK, MessageBoxIcon.Asterisk, MessageBoxDefaultButton.Button1);
                    return;
                }
                Training.MaxRunningTime = TimeSpan.FromMinutes((double)nmMaxMinutes.Value);
                Training.MaxDistance = (double)nmMaxDistance.Value;

                //avvio il training
                Training.StartTraining(MapPoint.FromGPSPosition(_CurrentPosition));
                cmdStart.Text = "End Training Session";

                _uman.RequestUnattendedMode();

                mapBox1.TrackDisplayed = Training.Track;               
            }
        }

        private void SaveData()
        {
            try
            {
                //salva file XML
                string filename = "\\my documents\\mkrunner-trackdata-" + DateTime.Now.ToString("yyyy-MM-dd-hh-mm") + ".xml";
                Training.TrainDataSet.WriteXml(filename, XmlWriteMode.WriteSchema);

                //salva file KML
                string kmlfilename="mkrunner-trackdata-" + DateTime.Now.ToString("yyyy-MM-dd-hh-mm") + ".kml";

                List<KMLCoordinates> lc = new List<KMLCoordinates>();
                foreach (PositionTrackDataSet.TrackRecordRow r in Training.TrainDataSet.TrackRecord.Rows)
                   lc.Add(new KMLCoordinates(r.Long,r.Lat,r.Alt));
             
                KMLLine RunningPath = new KMLLine(lc, DateTime.Now.ToString("yyyy-MM-dd-hh-mm"), "Training path from mkrunner");
                RunningPath.AltitudeMode = KMLAltitudeMode.Absolute;
                RunningPath.KMLFileName = kmlfilename;
                RunningPath.KMLFilePath = "\\my documents\\";
                RunningPath.Save();

                Training.TrainDataSet.Clear();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

        }

        private void tmrUpdateData_Tick(object sender, EventArgs e)
        {           
            try
            {
                Training.Tick();
                lblTime.Text = Training.RunningTime.Hours.ToString("00") + ":" + Training.RunningTime.Minutes.ToString("00") + ":" + Training.RunningTime.Seconds.ToString("00");
                lblDistance.Text = Training.RunningDistance.ToString("N0") + " M";
                lblRemainingTime.Text = Training.RemainingTime.Hours.ToString("00") + ":" + Training.RemainingTime.Minutes.ToString("00") + ":" + Training.RemainingTime.Seconds.ToString("00");
                lblRemainingDistance.Text = Training.RemainingDistance.ToString("N0"); Training.Tick();
                
            }
            catch { }
        }

        private void UpdateGPSUI()
        {
            //inizializzazione testi            
            lblLatitude.Text = "Lat: ";
            lblLongitude.Text = "Lon: ";
            lblAltitude.Text = "Alt: ";
            lblSNR.Text = "Sat: ";
            lblPDOP.Text = "PDOP: ";

            _gps_ok = false;

            //se non ho posizione esco
            if (_CurrentPosition == null)
            {
                lblGPSFront.ForeColor = Color.Red;
                lblFIX.Text = "No fix, no data";
                return;
            }
            lblSpeed.Text = (_CurrentPosition.Speed * 1.852).ToString("N1") + "Km/h";


            //calcolo SNR
            SolSnrAvg = 0;
            ViewSnrAvg = 0;
            try
            {
                Satellite[] UsedSatellites = _CurrentPosition.GetSatellitesInSolution();
                if (UsedSatellites != null && UsedSatellites.Length != 0)
                {
                    foreach (Satellite s in UsedSatellites)
                    {
                        SolSnrAvg += s.SignalStrength;
                    }
                    SolSnrAvg /= UsedSatellites.Length;
                }
            }
            catch { }
            try{
                Satellite[] ViewSatellites = _CurrentPosition.GetSatellitesInView();
                if (ViewSatellites != null && ViewSatellites.Length != 0)
                {
                    foreach (Satellite s in ViewSatellites)
                    {
                        ViewSnrAvg += s.SignalStrength;
                    }
                    ViewSnrAvg /= ViewSatellites.Length;
                }
            }
            catch { }           
            lblSNR.Text += "S:" + _CurrentPosition.SatelliteCount.ToString() + " Snr:" + SolSnrAvg.ToString("N1") + "db, ";
            lblSNR.Text += "V:" + _CurrentPosition.SatellitesInViewCount.ToString();

            lblPDOP.Text += _CurrentPosition.PositionDilutionOfPrecision.ToString("N1");

            if (_CurrentPosition.TimeValid==false || _CurrentPosition.Time==null)
            {
                //posizione ok ma niente tempo
                lblFIX.Text = "No Time Fix";
                lblGPSFront.ForeColor = Color.Red;
                return;
            }
                           
            if (Math.Abs(_CurrentPosition.Time.Subtract(DateTime.Now.ToUniversalTime()).TotalSeconds) > 50)                    
            {
                //posizione ok ma dato vecchio
                lblGPSFront.ForeColor = Color.Yellow;      
                lblFIX.Text = "Cached Fix,";
                lblFIX.Text += _CurrentPosition.Time.ToString("hh:mm:ss dd/MM/yyyy");
                return;
            }

            lblFIX.Text = "Fix,";
            lblFIX.Text += _CurrentPosition.Time.ToString("hh:mm:ss dd/MM/yyyy");

            if (SolSnrAvg < 15 && _CurrentPosition.SatelliteCount < 4 || _CurrentPosition.PositionDilutionOfPrecision>8)
            {
                lblGPSFront.ForeColor = Color.Yellow;
                return;
            }
            
            lblLatitude.Text += _CurrentPosition.Latitude.ToString("N10");
            lblLongitude.Text += _CurrentPosition.Longitude.ToString("N10");
            lblAltitude.Text += _CurrentPosition.SeaLevelAltitude.ToString("N0") + " mSLM";

            _gps_ok = true;
            
            lblGPSFront.ForeColor = Color.LimeGreen;
        }

        private void mnuLock_Click(object sender, EventArgs e)
        {
            try
            {
                PowerManager.SetRequirement("BKL1:", CEDEVICE_POWER_STATE.D4);
                PowerManager.SetPower("BKL1:", CEDEVICE_POWER_STATE.D4);
            }
            catch { }
            
            VKeyManager.LockKeypad();
        }

        private void menuItem1_Click(object sender, EventArgs e)
        {
            if (!Training.IsRunning)
            {
                this.Close();
            }
        }

        private void tmrgps_Tick(object sender, EventArgs e)
        {
            
            GpsPosition p=null;
            GpsDeviceState s=null;
           
            try  {
                s = _gps.GetDeviceState();
                lblStatus.Text = s.FriendlyName + " " + s.DeviceState.ToString();
            }
            catch {
                lblStatus.Text = "ERR";
            }

            try {
                p= _gps.GetPosition();

                _CurrentPosition = p;
           
                UpdateGPSUI();
            }
            catch {
                lblSpeed.Text = "ERR";
            }

            //se la posizione è valida
            //aggiorno i dati di allenamento
            if (Training.IsRunning 
                && _CurrentPosition != null 
                && _CurrentPosition.LongitudeValid 
                && _CurrentPosition.LatitudeValid 
                && _CurrentPosition.SeaLevelAltitudeValid 
                && _CurrentPosition.SpeedValid
                && _CurrentPosition.TimeValid
                )
                Training.UpdatePosition(MapPoint.FromGPSPosition(_CurrentPosition));
        }



    }
}